# -*- coding: utf-8 -*-
import wx
import datetime

"""
this file implements each item representing a single day
"""
class SimpleCalendarItem(wx.Window):
    """
    implements each item representing a single day
    """
    TIMER_INTERVAL = 200

    def __init__(self, parent, date, items, width = 200, length = 400,
                 title_height = 20, event_mode = 1,#let parent handle this
                 titleground = '#eaf1f7', foreground = '#8cf0ec',
                 foreground2 = '#90fffc',
                 selectground = '#8cf0ec', background = '#fafbfd',
                 fontsize = 10, mode = "BIG"):
        """
        graphics initialization
        """
        wx.Window.__init__(self, parent, size = (width, length),
                           style=wx.RAISED_BORDER)

        self.timer = wx.Timer()
        #deal with flicker
        self.SetDoubleBuffered(True)
        #faster!
        wx.ToolTip.SetDelay(200)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.on_lbutton_down)
        self.Bind(wx.EVT_LEFT_UP, self.on_lbutton_up)
        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.on_leave_window)
        self.timer.Bind(wx.EVT_TIMER, self.on_timer)

        self.tip_window = None

        #copy or share?
        self.list = items
        self.foreground = foreground
        self.foreground2 = foreground2
        self.background = background
        self.titleground = titleground
        self.selectground = selectground

        self.font_size = fontsize
        self.mode = mode
        self.event_mode = event_mode
        self.date = date
        self.datestr = date.strftime("%a %m-%d")
        self.title_height = title_height

        self.mouse_state = 0
        self.timer_state = 0
        self.shit = 0

        #why am I doing this?
        #because I found that sometimes OnSize is not called before
        #OnDraw, and that caused me trouble, so I do this myself
        self.OnSize(None)

        

    def OnSize(self, evt):
        size = self.GetClientSize()
        self.width = size[0]
        self.length = size[1]
        self._buffer = wx.EmptyBitmap(size[0], size[1])
        self._buffer_select = None
        self.update()


    def add(self, start, end, event, udata=None, color=None):
        """
        NOTE:these are NOT USED
        add event into a day
        start: hour from 0(if you have minite, use float)
        end: hour from 0(if you have minite, use float)
        udata: user data, perhaps a reference to model object
        """
        self.list.append((start, end, event, color, udata))

    def remove(self, start, end):
        """
        NOTE:these are NOT USED
        remove a event from a day
        """
        for i in self.list:
            if i[0] == start and i[1] == end:
                break
        self.list.remove(i)

    def update(self):
        """
        sync data and UI
        """
        dc = wx.MemoryDC()
        dc.SelectObject(self._buffer)
        self.Draw(dc)
        #need to get rid of the MemoryDC before Update() is called. I do not know why
        del dc
        self.Refresh(eraseBackground=True)
        self.Update()


    def OnPaint(self, evt):
        if self.mouse_state == 0 or self._buffer_select == None:
            dc = wx.BufferedPaintDC(self, self._buffer)
        else:
            dc = wx.BufferedPaintDC(self, self._buffer_select)
        #print("on paint")

    def Draw(self, dc):
        """
        dc unrelated pain, content provider
        repaint this single day
        """
        dc.SetBackground(wx.Brush(self.background))
        dc.Clear()
        dc.SetFont(wx.Font(self.font_size, wx.SWISS, wx.NORMAL, wx.BOLD))
        default_brush = wx.Brush(self.foreground)
        
        H = self.title_height
        L = self.length - H
        W = self.width
        line_limit = (W - self.font_size*2)/self.font_size

        #date title
        dc.SetBrush(wx.Brush(self.titleground))
        dc.SetPen(wx.Pen('grey', style=wx.TRANSPARENT))
        dc.DrawRectangle(0, 0, W, H)
        dc.DrawText(self.datestr, 0, 0)

        #body
        if self.list == None:
            return
        for i in self.list:
            y1 = i[0] * L / 24
            y2 = i[1] * L / 24
            if i[3] == None:
                dc.SetBrush(default_brush)
                color = self.foreground
            else:
                dc.SetBrush(wx.Brush(i[3]))
                color = i[3]
            #print(y1,y2)
            dc.SetPen(wx.Pen('grey', style=wx.TRANSPARENT))
            dc.DrawRectangle(0, y1+H, W, y2-y1)
            #color = int(color[1:], 16)
            #c1 = wx.Colour()
            #c1.SetRGB(color)
            #c2 = wx.Colour()
            #c2.SetRGB(color + 0x0)
            #dc.GradientFillLinear((0, y1+H, W, y2-y1),
            #                      c1, c2, wx.NORMAL)
            
            if self.mode != 'BIG':
                #do not draw any text in SMALL mode
                continue
            dc.SetPen(wx.Pen(wx.BLACK, 4))
            dc.DrawText("%02d:%02d"%(i[0],(i[0]-int(i[0]))*60), 0, y1+H)
            #I want upperbound of time to be in the box
            dc.DrawText("%02d:%02d"%(i[1],(i[1]-int(i[1]))*60), 0, y2-self.font_size*2+H)
            #make sure that text can be pretty, or we only draw part of them
            lc = int((y2-y1 - self.font_size*4) / (self.font_size*2))
            sz = len(i[2])
            pos = 0
            st = i[2]
            for idx in range(1,lc+1):
                if sz > line_limit:
                    dc.DrawText(st[pos:pos + line_limit], self.font_size,
                                y1+self.font_size*2*idx+H)
                    pos = pos + line_limit
                    sz -= line_limit
                else:
                    dc.DrawText(st[pos:], self.font_size, y1 + self.font_size*2*idx+H)
                    break

    def on_lbutton_down(self, evt):
        """
        used to deal with drag
        """
        #dc = wx.PaintDC(self)
        self.mouse_state = 1 # L button is down
        self.spos = evt.GetPosition()[1]
        #print(pos)

    def on_lbutton_up(self, evt):
        """
        used to deal with drag
        """
        self.mouse_state = 0 # L button is up
        self._buffer_select = None
        #TODO:perhaps get rid of the select window first?
        #TODO:popup window please
        self.update()
        epos = evt.GetPosition()[1]

        #should pass these args to parent
        
        data = (self.date, self.y_to_time_int(self.spos), self.y_to_time_int(epos))
        if self.event_mode == 1:#we do it
            evt = wx.PyCommandEvent(EVT_SELECTED.typeId, self.GetId())
            evt.mydata = data
            evt.SetEventObject(self)
            self.GetEventHandler().ProcessEvent(evt)
        else:#let parent send it out
            self.GetParent().deal_on_select(data)
            #print(self.GetParent())

    def on_motion(self, evt):
        """
        when we move, the timer will be reset(so if
        you keep moving, tip will notcome out)
        """
        # L button is up, we do not need to show selection area
        if self.tip_window:
            self.tip_window = None
            self.SetToolTip(None)
        if self.mouse_state == 0:
            #deal with timer
            self.timer.Stop()
            self.timer.Start(self.TIMER_INTERVAL, oneShot=True)
            return
        #draw selection rectangle
        pos = evt.GetPosition()[1]
        #Now we have to do it in a clean way, draw the selection using refresh
        #on linux, we can use elegal method and get away with it, but on window
        #shit NO!
        self.draw_selection(pos)


    def draw_selection(self, pos):
        dc = wx.MemoryDC()
        self._buffer_select = wx.BitmapFromImage(wx.ImageFromBitmap(self._buffer))
        dc.SelectObject(self._buffer_select)
        dc.SetFont(wx.Font(self.font_size, wx.SWISS, wx.NORMAL, wx.BOLD))
        #background
        dc.SetBrush(wx.Brush(self.selectground))
        sz = self.GetClientSize()
        W = sz[0]
        dc.DrawRectangle(0, self.spos, W, pos-self.spos)
        dc.DrawText(self.y_to_time(pos), 0, pos)
        #they said we need to get rid of dc before calling Refresh. I do not
        #know why
        del dc
        self.Refresh(eraseBackground=True)
        self.Update()

    def on_enter_window(self, evt):
        pass
        #self.tip_window = wx.ToolTip("")
        #self.SetToolTip(self.tip_window)
    def on_leave_window(self, evt):
        try:
            self.timer.Stop()
            self.SetToolTip(None)
            #TODO:get rid of the time text
        except:
            #no timer, it's still ok
            pass

    def on_timer(self, evt):
        #so user hasn't move his mouse for 1s, display time cursor
        pos = self.ScreenToClient(wx.GetMousePosition())
        #there should be no tip windows till now, so create it
        #tip = wx.TipWindow(self.GetParent(), self.y_to_time(pos[1]))
        #we need this to make tip window disappear when mouse moved away
        #tip.SetBoundingRect(wx.Rect(pos[0]-1000,pos[1]-1000, 1000, 10000))
        #self.SetToolTipString(self.y_to_time(pos[1]))
        self.tip_window = wx.ToolTip(self.y_to_time(pos[1]))
        self.SetToolTip(self.tip_window)

    def y_to_time(self, y):
        hour, minute = self.y_to_time_int(y)
        return "%02d:%02d"%(hour,minute)

    def y_to_time_int(self, y):
        H = self.title_height
        L = self.length - H
        y -= H
        time = y*24.0/L
        hour = int(time)
        minute = int((time - hour) * 60)
        return hour, minute


EVT_SELECTED = wx.PyEventBinder(wx.NewEventType(), 1)

#class TestFrame(wx.Frame):
class TestFrame(wx.ScrolledWindow):
    def __init__(self, parent):
        #wx.Frame.__init__(self, parent,
        #                  size = (500,500),
        #                  title="Double Buffered Test",
        #                  style=wx.DEFAULT_FRAME_STYLE)
        #sizer = wx.BoxSizer(wx.HORIZONTAL)
        wx.ScrolledWindow.__init__(self, parent, -1)
        self.SetScrollbars(1, 1, 1400, 1800)
        sizer = wx.GridBagSizer()
        poly1 = SimpleCalendarItem(self, datetime.datetime.today()-datetime.timedelta(1), [])
        poly2 = SimpleCalendarItem(self, datetime.datetime.today(), [])
        self.Bind(EVT_SELECTED, self.on_select, poly1)
        self.Bind(EVT_SELECTED, self.on_select, poly2)
        sizer.Add(poly1, (0,0))
        sizer.Add(poly2, (1,0))
        #sizer.Add(poly1, 0)
        #sizer.Add(poly2, 0)
        poly1.add(1,5,"1")
        poly1.add(8,12,"2")
        poly1.add(13,15,"3456")
        poly2.add(13,15,"3456")

        self.SetSizer(sizer)
        self.Show()

    def on_select(self, evt):
        d, s, e = evt.mydata
        print("%s\nstart:%02d:%02d\nend:%02d:%02d"%(d, s[0], s[1], e[0], e[1]))



if __name__ == '__main__':
    app = wx.App()
    p = wx.Frame(None,-1,'TestFrame')
    f = TestFrame(p)
    p.Show()
    app.MainLoop()
